﻿
using DataService.Core.Extensions;

using DataService.IService;
using System;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.Threading;
using DataService.Core.Common;
using DataService.Core.ServiceDTO;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Data.SQLite;
using DataService.Cache.Caching;

namespace DataService.Common
{
    public abstract class DatabaseProvider : DisposeBase, IDatabaseProvider
    {
        /// <summary>数据库类型</summary>
        public abstract DatabaseType DBType { get; }
        public abstract Type DatabaseProviderType { get; }
        public bool IsEnable { get; set; } = false;

        /// <summary>数据库提供者工厂</summary>
        public abstract DbProviderFactory ProviderFactory { get; }
        /// <summary>分表后缀</summary>
        public virtual String TableSuffix { get; set; }


        /// <summary>链接字符串</summary>
        public String ConnectionString { get; set; }


        /// <summary>数据库名</summary>
        public String DatabaseName { get; set; }


        public virtual IsolationLevel _IsolationLevel { get; set; } = IsolationLevel.ReadCommitted;

        private static int _exchangeLock = 0;
        /// <summary>
        /// 释放已经提交/释放 事务；
        /// true:已经执行
        /// false:未执行
        /// </summary>
        private bool _commitRollbackFlag = false;


        protected DbConnection _DbConnection;
        protected DbTransaction _Transaction;
        public virtual DbConnection DbConnection
        {
            get
            {
                if (string.IsNullOrEmpty(ConnectionString))
                {
                    throw new ArgumentException("请配置数据库连接");
                }
                if (_DbConnection != null)
                {
                    return _DbConnection;
                }
                lock (typeof(DatabaseProvider))
                {
                    if (_DbConnection != null)
                    {
                        return _DbConnection;
                    }
                    DbConnection dbConnection = ProviderFactory.CreateConnection();
                    dbConnection.ConnectionString = ConnectionString;
                    dbConnection.Open();
                    _DbConnection = dbConnection;

                }
                return _DbConnection;
            }
        }

        public virtual DbTransaction Transaction
        {
            get
            {
                if (_Transaction != null)
                {
                    return _Transaction;
                }
                if (_DbConnection == null)
                {
                    var stackFrames = StackFrameHelper.GetStackFrame();
                    string frameStr = string.Join(">", stackFrames);
                    DataService.Core.Log.TraceLog.WriteLine($"线程：{Thread.CurrentThread.ManagedThreadId},连接为空，数据库连接：{ConnectionString}，调用顺序：{frameStr}", "数据库");
                }
                lock (typeof(DatabaseProvider))
                {
                    if (_Transaction != null)
                    {
                        return _Transaction;
                    }
                    _Transaction = _DbConnection.BeginTransaction(_IsolationLevel);
                    _commitRollbackFlag = false;
                }
                return _Transaction;
            }
        }


        private string _ServerName;
        /// <summary>服务器</summary>
        public String ServerName
        {
            get
            {
                if (!string.IsNullOrWhiteSpace(_ServerName)) return _ServerName;
                if (string.IsNullOrWhiteSpace(ConnectionString))
                {
                    return string.Empty;
                }
                var dic = ConnectionString.SplitAsDictionary("=", ";", true);
                dic.TryGetValue("Server", out string serverName);
                if (!string.IsNullOrWhiteSpace(serverName))
                {
                    _ServerName = serverName;
                }
                return _ServerName;
            }
            set
            {
                _ServerName = value;
            }
        }

        private String _User;
        /// <summary>用户名UserID</summary>
        public String User
        {
            get
            {
                if (_User != null) return _User;

                var connStr = ConnectionString;

                if (String.IsNullOrEmpty(connStr)) return null;

                var ocsb = ProviderFactory.CreateConnectionStringBuilder();
                ocsb.ConnectionString = connStr;

                if (ocsb.ContainsKey("User ID"))
                    _User = (String)ocsb["User ID"];
                else if (ocsb.ContainsKey("User"))
                    _User = (String)ocsb["User"];
                else if (ocsb.ContainsKey("uid"))
                    _User = (String)ocsb["uid"];
                else
                    _User = String.Empty;

                return _User;
            }
        }
        private string _schema;
        /// <summary>
        /// 访问模式
        /// </summary>
        public string Schema
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_schema))
                {
                    _schema = User;
                }
                return _schema;
            }
            set
            {
                _schema = value;
            }
        }


        public virtual void Commit()
        {
            if (_Transaction != null)
            {
                _Transaction.Commit();
                _Transaction.TryDispose();
                _Transaction = null;
                _commitRollbackFlag = true;
            }
        }
        //public virtual void Save()
        //{
        //    _Transaction.Commit();
        //    _Transaction.TryDispose();
        //}
        public virtual void Rollback()
        {
            if (_Transaction != null)
            {
                _Transaction.Rollback();
                _Transaction.TryDispose();
                _Transaction = null;
                _commitRollbackFlag = true;
            }
        }

        /// <summary>
        /// 释放其他非托管资源；
        /// Connection, DataReader 建议在调用处 使用using或者 Dispose释放对象
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(Boolean disposing)
        {

            //析构函数中应当只是放类的非托管成员
            //不要再析构函数中调用Connection, DataReader,或其他托管对象的Close()或Dispose()方法，
            base.Dispose(disposing);
            if (_Transaction != null)
            {
                //需要先判断对象是否已释放
                //如果忘记提交事务 这里是否自动提交(_Transaction.Commit())？GC执行不确定，以后再优化这里
                if (!_commitRollbackFlag)
                {
                    try
                    {
                        //调用层，没有执行 提交/回滚动作，这里尝试 提交 动作
                        _Transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        _Transaction.Rollback();
                        var stackFrames = StackFrameHelper.GetStackFrame();
                        string frameStr = string.Join(">", stackFrames);
                        DataService.Core.Log.TraceLog.WriteLine($"线程：{Thread.CurrentThread.ManagedThreadId}，调用者没有执行 提交/回滚动作，【自动提交事务】失败，事务进行回滚，调用顺序：{frameStr}", "事务");
                    }
                }
                _Transaction.TryDispose();
            }
            if (_DbConnection != null)
            {
                _DbConnection.TryDispose();
            }

        }
        /// <summary>
        /// 返回数据库工厂
        /// </summary>
        /// <param name="assemblyFile">dll文件，如 xxx.dll或 dll绝对路径</param>
        /// <param name="className">类名限定名；命名空间.类名 如 System.Data.SqlClient.SqlClientFactory</param>
        /// <returns></returns>
        protected DbProviderFactory GetProviderFactory(string assemblyFile, string className)
        {
            if (string.IsNullOrEmpty(assemblyFile))
            {
                throw new ArgumentOutOfRangeException("缺少必要的*参数*");
            }
            //若dll不存在 则尝试从nuget下载，以后在优化这里
            Assembly assembly = Assembly.LoadFrom(assemblyFile);
            Type type = assembly.GetType(className);
            FieldInfo fieldInfo = type.GetField("Instance");
            var dbProviderFactory = MemberInfoHelper.GetMemberValue(null, fieldInfo) as System.Data.Common.DbProviderFactory;
            return dbProviderFactory;
        }

    }
}
